﻿using Neo4j.Driver;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;

namespace WinFormsApp1
{
    internal class KnowlgeMapToNeo4j<T>
    {
        private Neo4JServe m_client;
        public string EntityTableName { get; set; } = "SimpleTaskEntity";
        public string EntityName { get; set; } = "taskEntity";

        /// <summary>
        /// 初始化以构建连接
        /// </summary>
        public void Initialize()
        {
            m_client=new Neo4JServe();
            m_client.Initialize();
        }

        #region 1-1 新增实体
        public async Task AddTaskEntityAsync(List<T> people)
        {
            try
            {
                var query = m_client.Client.Cypher
                   .Unwind(people, EntityName)
                   .Create("(p:"+ EntityTableName + ")")
                   .Set("p = "+ EntityName);

                await query.ExecuteWithoutResultsAsync();
            }
            catch (Exception err)
            {
                MessageBox.Show("失败" + err.Message);
            }
        }
        internal void SaveEntity(T createdEntity)
        {
            AddTaskEntityAsync(new List<T>() { createdEntity });
        }
        #endregion

        #region 2-1 添加关系
        public async Task SaveRelation(CommonRelation relation)
        {
            if (relation.properties.ContainsKey("relationshipType") == false)
            {
                relation.properties.Add("relationshipType", relation.type);
            }
            if (relation.properties.ContainsKey("type") == false)
            {
                relation.properties.Add("type", relation.type);
            }

            try
            {
                await m_client.Client.Cypher
                .Match("(a:" + relation.startNodeType + ")", "(b:" + relation.endNodeType + ")")
                .Where((ICommonEntity a) => a.id == relation.startNode)
                .AndWhere((ICommonEntity b) => b.id == relation.endNode)
                .Create("(a)-[r:RELATIONSHIP $props]->(b)")
                .WithParam("props", relation.properties)
                .ExecuteWithoutResultsAsync();
            }
            catch (Exception err)
            {
                throw;
            }
        }

        /// <summary>
        /// 注意，所有的properties都一样
        /// </summary>
        /// <param name="bulkRelations"></param>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        public async Task SaveRelationsBatchAsync2(List<CommonRelation> bulkRelations)
        {
            if (bulkRelations == null || bulkRelations.Count == 0)
                return;

            try
            {
                var relation = bulkRelations[0];
                if (!relation.properties.ContainsKey("relationshipType"))
                    relation.properties.Add("relationshipType", relation.type);

                if (!relation.properties.ContainsKey("type"))
                    relation.properties.Add("type", relation.type);

                // 使用 UNWIND 实现批量插入（Neo4jClient 支持的方式）
                var query = m_client.Client.Cypher
                    .Unwind(bulkRelations, "rel")
                    .Match($"(a:{bulkRelations[0].startNodeType} {{ id: rel.startNode }})")  // 假设所有关系类型相同
                    .Match($"(b:{bulkRelations[0].endNodeType} {{ id: rel.endNode }})")
                    .Create("(a)-[r:RELATIONSHIP $props]->(b)")
                    .WithParam("props", bulkRelations[0].properties);
                    //.Set("r = rel.properties");

                await query.ExecuteWithoutResultsAsync();
            }
            catch (Exception ex)
            {
                throw new Exception("批量保存关系失败: " + ex.Message, ex);
            }
        }

        public async Task SaveRelationsBatchAsync(List<CommonRelation> bulkRelations)
        {
            if (bulkRelations == null || bulkRelations.Count == 0)
                return;

            try
            {
                // 预处理属性
                var relation = bulkRelations[0];
                if (!relation.properties.ContainsKey("relationshipType"))
                    relation.properties.Add("relationshipType", relation.type);

                if (!relation.properties.ContainsKey("type"))
                    relation.properties.Add("type", relation.type);

                // 动态批次大小
                int batchSize = Math.Min(100, bulkRelations.Count);
                int totalBatches = (int)Math.Ceiling((double)bulkRelations.Count / batchSize);

                for (int batchIndex = 0; batchIndex < totalBatches; batchIndex++)
                {
                    var batch = bulkRelations
                        .Skip(batchIndex * batchSize)
                        .Take(batchSize)
                        .ToList();

                    await ProcessBatchAsync(batch, batchIndex + 1, totalBatches);
                }
            }
            catch (Exception ex)
            {
                throw new Exception("批量保存关系失败: " + ex.Message, ex);
            }
        }

        private async Task ProcessBatchAsync(List<CommonRelation> batch, int currentBatch, int totalBatches)
        {
            if (batch == null || batch.Count == 0)
                return;

            try
            {
                Console.WriteLine($"处理批次 {currentBatch}/{totalBatches} ({batch.Count} 条关系)");

                // 按节点类型分组处理
                var groupedByType = batch
                    .GroupBy(r => new { StartType = r.startNodeType, EndType = r.endNodeType });

                foreach (var group in groupedByType)
                {
                    var relationsInGroup = group.ToList();

                    var query = m_client.Client.Cypher
                        .Unwind(relationsInGroup, "rel")
                        .Match($"(a:{group.Key.StartType} {{ id: rel.startNode }})")
                        .Match($"(b:{group.Key.EndType} {{ id: rel.endNode }})")
                        .Create("(a)-[r:RELATIONSHIP $props]->(b)")
                        .WithParam("props", batch[0].properties);

                    await query.ExecuteWithoutResultsAsync();
                }
            }
            catch (Exception ex)
            {
                throw new Exception($"处理批次 {currentBatch}/{totalBatches} 失败: {ex.Message}", ex);
            }
        }
        internal async Task CreateRelationshipAsync(List<CommonRelation> zz_auto_conver_relations)
        {
            await SaveRelationsBatchAsync(zz_auto_conver_relations);
        }
        #endregion

        internal void Dispose()
        {
            m_client?.Dispose();
        }

        
    }
}
